﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using psafth.FSR.Lapcounter;
using System.Linq.Expressions;
using System.Reflection;
using psafth.AMB;

namespace LapShowerForm
{
    public partial class Form1 : Form
    {
        private Heat _heat;
        private bool _runTimer = false;
        private List<RaceCompetitor> _competitors;

        private DateTime StopTime;

        BackgroundWorker _bg;

        public Form1()
        {
            InitializeComponent();

            DataGridView t = new DataGridView();

            DataGridViewTextBoxColumn tb_StartNumber = new DataGridViewTextBoxColumn();
            tb_StartNumber.HeaderText = "Startnummer";
            tb_StartNumber.Name = "Startnumber";
            tb_StartNumber.DataPropertyName = "Startnumber";

            DataGridViewTextBoxColumn tb_name = new DataGridViewTextBoxColumn();
            tb_name.HeaderText = "Namn";
            tb_name.Name = "Name";

            DataGridViewTextBoxColumn tb_licence = new DataGridViewTextBoxColumn();
            tb_licence.HeaderText = "Licensnummer";
            tb_licence.Name = "Licence";

            DataGridViewTextBoxColumn tb_laps = new DataGridViewTextBoxColumn();
            tb_laps.HeaderText = "Varv";
            tb_laps.Name = "Laps";

            DataGridViewTextBoxColumn tb_bestlap = new DataGridViewTextBoxColumn();
            tb_bestlap.HeaderText = "Bästa varvtid";
            tb_bestlap.Name = "Bestlap";

            DataGridViewTextBoxColumn tb_lastlap = new DataGridViewTextBoxColumn();
            tb_lastlap.HeaderText = "Senaste varvtid";
            tb_lastlap.Name = "Lastlap";

            raceDataGridView.Columns.Add(tb_StartNumber);
            raceDataGridView.Columns.Add(tb_name);
            raceDataGridView.Columns.Add(tb_licence);
            raceDataGridView.Columns.Add(tb_laps);
            raceDataGridView.Columns.Add(tb_bestlap);
            raceDataGridView.Columns.Add(tb_lastlap);

            UpdateDGW();

            psafth.FSR.Lapcounter.DbEntities db = new DbEntities();
            psafth.FSR.Lapcounter.HeatDriver ht = new HeatDriver();

            this._competitors = new List<RaceCompetitor>();

            this.WindowState = FormWindowState.Normal;
            this.FormBorderStyle = FormBorderStyle.FixedToolWindow;
            this.WindowState = FormWindowState.Normal;
            
            _bg = new BackgroundWorker();
            _bg.WorkerReportsProgress = true;

            _bg.ProgressChanged += bg_ProgressChanged;

            this.middleCenterLabel.Text = "Inga pågående heat";
            this.middleCenterLabel.Dock = DockStyle.Fill;
            this.middleCenterLabel.AutoSize = false;
            this.middleCenterLabel.TextAlign = ContentAlignment.MiddleCenter;
            this.middleCenterLabel.Font = new Font(DefaultFont.FontFamily, 20, FontStyle.Bold);
            this.raceDataGridView.Visible = false;


            this.lblHeaderText.Visible = false;
            this.lblTimer.Visible = false;

            _bg.DoWork += bg_DoWork;

            _bg.RunWorkerAsync();

        }

        void bg_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            if (e.UserState != null)
            {
                if (e.UserState.GetType().Equals(typeof(HeatCommand)))
                {
                    _heat = ((HeatCommand)e.UserState).Heat;
                    _competitors = ((HeatCommand)e.UserState).Competitors;


                    this.lblHeaderText.Text = _heat.DisplayTitle;
                    this.lblTimer.Text = _heat.HeatDuration + ":00.000";

                    this.middleCenterLabel.Visible = false;
                    this.lblHeaderText.Visible = true;
                    this.lblTimer.Visible = true;
                    this.raceDataGridView.Visible = true;

                    UpdateDGW();
                }

                if (e.UserState.GetType().Equals(typeof(List<RaceCompetitor>)))
                {
                    _competitors = (List<RaceCompetitor>)e.UserState;

                    _competitors.OrderBy(c => c.Laps.Count).ThenBy(c => c.Laps.Last().PassingTime);

                    UpdateDGW();
                }

                if (e.UserState.GetType().Equals(typeof(StartCommand)))
                {
                    StartCommand s = (StartCommand)e.UserState;
                    this.StopTime = DateTime.Now.Add(s.HeatDurationLeft);
                    _runTimer = true;
                }

                if (e.UserState.GetType().Equals(null))
                {
                    this.lblHeaderText.Text = string.Empty;
                    this.lblTimer.Text = string.Empty;

                    this.middleCenterLabel.Visible = true;
                    this.lblHeaderText.Visible = false;
                    this.lblTimer.Visible = false;
                }
            }
        }

        void bg_DoWork(object sender, DoWorkEventArgs e)
        {
            UdpClient client = new UdpClient();

            client.ExclusiveAddressUse = false;
            IPEndPoint localEp = new IPEndPoint(IPAddress.Any, 2222);

            client.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
            client.ExclusiveAddressUse = false;

            client.Client.Bind(localEp);

            IPAddress multicastaddress = IPAddress.Parse("239.0.0.222");
            client.JoinMulticastGroup(multicastaddress);

            
            while (true)
            {
                byte[] data = client.Receive(ref localEp);

                _bg.ReportProgress(1, MulticastHelper.ByteArrayToObject(data));
            }
        }

        private void timerControl_Tick(object sender, EventArgs e)
        {
            if (_runTimer)
            {
                TimeSpan s = StopTime.Subtract(DateTime.Now);

                lblTimer.Text = s.ToString(@"mm\:ss");
            }
        }

        //Set method invoked by background thread
        private void UpdateDGW()
        {
            try
            {
                // Find the index of the competitor.
                int index = -1;

                raceDataGridView.Rows.Clear();

                foreach (RaceCompetitor c in _competitors)
                {
                    

                    raceDataGridView.Rows.Add(c.StartNumber, c.FirstName + " " + c.SurName, c.LicenceNumber, c.Laps.Count, c.BestLap, c.PreviousLap.LapTime);

                    // TODO: _stopRace changed to compare time intervals.
                    if (c.Laps.Count > 0 && c.Laps.Last().PassingTime > StopTime)
                    {
                        raceDataGridView.Rows[index].DefaultCellStyle.ForeColor = Color.LightGray;
                    }

                    raceDataGridView.Rows[index].Cells[4].Value = c.Laps.Count(l => l.IsValid == true);

                    // TODO: _stopRace changed to compare time intervals.
                    if (c.Laps.Count > 0 && c.Laps.Last().PassingTime > StopTime)
                    {
                        if (c.EndTime < 0)
                        {
                            raceDataGridView.Rows[index].Cells[3].Value += " (DSQ)";
                        }
                        else
                        {
                            raceDataGridView.Rows[index].Cells[3].Value += string.Format(" ({0}s)", AMBCalculator.TrimDouble(c.EndTime, 3));
                        }
                    }
                }


                raceDataGridView.ClearSelection();
                raceDataGridView.Update();
                raceDataGridView.ClearSelection();


            }
            catch (Exception)
            {
                // TODO: Log, then nothing.
            }
        }
    }
}
